import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { RechargeOrder } from 'src/entities/RechargeOrder';
import { UserWallet } from 'src/entities/UserWallet';
import { UserWalletLog } from 'src/entities/UserWalletLog';
import { PaymentService } from 'src/payment/payment.service';
import { RedisService } from 'src/redis/redis.service';
import { getTime } from 'src/util';
import { Connection } from 'typeorm';
import { AppletService } from '../applet/applet.service';
import { UserService } from '../user/user.service';

@Injectable()
export class RechargeService {
    private rechargeOrderKey:string;
    private rechargeOrderStatusKey:string;

    constructor(
        private configService:ConfigService,
        private redis:RedisService,
        private appletService:AppletService,
        private payment:PaymentService,
        private userService:UserService,

        private connection: Connection,
    ) {
        this.rechargeOrderKey = this.configService.get<string>('cacheKey.rechargeOrder')
        this.rechargeOrderStatusKey = this.configService.get<string>('cacheKey.rechargeOrderStatus')
    }

    async recharge(amount:number, userId:number, clientSource:ClientSource) {
        let time = getTime()
        let orderNo = time + '' + userId
        let ordeData:{[key in keyof RechargeOrder]? : RechargeOrder[key]} = {
            orderNo : orderNo,
            amount : String(amount),
            rewardAmount : String(0),
            payChannel : clientSource,
            userId,
            status : 0,
            createTime : time
        }

        let applet = await this.appletService.applet(clientSource)

        this.payment.wxV3Certificates(applet)

        return false


        if(!applet) return false

        let user = await this.userService.getUserByUserId(userId)
        if(!user) return false

        try {
            let payParams = await this.payment.wechatPayment({
                openid : user.openid,
                appid : applet.appid,
                mchid : applet.mchid,
                orderNo : orderNo,
                total : amount,
                notifyUrl : applet.notifyUrl,
                privateKey : applet.privateKey,
                serialNo : applet.serialNo
            })

            if(payParams) {
                this.redis.set(orderNo, ordeData, 'EX', 90)
            }

            

            return payParams

        } catch (error) {
            console.log(error)   
        }

        return false
        
    }


    async rechargeNotify(body:WxPay.NotifyBody, headers:WxPay.NotifyHeaders) {
        if((await this.redis.set(body.id, '', 'EX', 10, 'NX')) == false) {
            return
        }

        console.log('has lock')

        let applet = await this.appletService.applet(1)
        if(!applet) return false
        const data = this.payment.wxNotify(body, headers, applet.v3apiSecret)
        if(data.trade_state === 'SUCCESS') {
            const orderNo = data.out_trade_no
            const order = await this.redis.get<RechargeOrder>(orderNo)
            if(!order) return true  //订单不存在,不继续处理了

            const amount = Number(order.amount)
            const rewardAmount = Number(order.rewardAmount)

            if(amount * 100 != data.amount.payer_total) return true

            const time = getTime()

            order.status = 1
            order.tradeNo = data.transaction_id
            order.payTime = Math.floor((new Date(data.success_time)).getTime() / 1000)

            

            const queryRunner = this.connection.createQueryRunner();
            await queryRunner.connect();
            await queryRunner.startTransaction()


            try {
                
                const userId = order.userId

                let wallet = await queryRunner.manager.findOne<UserWallet>(UserWallet, {
                    where : {userId : userId},
                    select : ['amount', 'rewardAmount'],
                    lock : {
                        mode : 'pessimistic_read'
                    }
                })

                let walletUpdate:{amount? : string, rewardAmount? : string} = {}
                let walletLog:{[key in keyof UserWalletLog]? : UserWalletLog[key]} = {
                    userId,
                    beforeAmount : wallet.amount,
                    beforeRewardAmount : wallet.rewardAmount,
                    type : 1,
                }

                walletUpdate.amount = String(Number(wallet.amount) + amount)
                walletLog.amount = order.amount
                walletLog.afterAmount = walletUpdate.amount


                if(rewardAmount > 0) {
                    walletUpdate.rewardAmount = String(Number(wallet.rewardAmount) + rewardAmount)
                    walletLog.rewardAmount = order.rewardAmount
                    walletLog.afterRewardAmount = walletUpdate.rewardAmount
                }

                {
                    //更新钱包
                    const { raw } = await queryRunner.manager.update<UserWallet>(UserWallet, { userId }, walletUpdate)
                    if(!raw || raw.affectedRows < 1) {
                        await queryRunner.rollbackTransaction()
                        return false
                    }
                }

                {
                    //加入充电订单
                    const { raw } = await queryRunner.manager.insert<RechargeOrder>(RechargeOrder, order)
                    if(!raw || raw.affectedRows < 1) {
                        await queryRunner.rollbackTransaction()
                        return false
                    }
                    walletLog.relationId = raw.insertId
                }

                {
                    //加入钱包明细
                    walletLog.createTime = time
                    const { raw } = await queryRunner.manager.insert<UserWalletLog>(UserWalletLog, walletLog)
                    if(!raw || raw.affectedRows < 1) {
                        await queryRunner.rollbackTransaction()
                        return false
                    }
                }

                await queryRunner.commitTransaction()

                this.redis.del(orderNo)

                console.log('success')

                return true

            } catch (error) {
                console.log(error)
                await queryRunner.rollbackTransaction()
            } finally{
                this.redis.del(body.id)
                await queryRunner.release()
            }

            console.log('fail')
            
            return false

        }else {
            this.redis.del(body.id)
            return true
        }
        
    }
}
